{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 大规模量子近似优化分治算法\n",
    "\n",
    "<em> Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved. </em>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概览\n",
    "\n",
    "[量子近似优化算法](./QAOA_CN.ipynb)（quantum approximate optimization algorithm, QAOA）是一个将量子与经典结合起来，用于解决组合优化问题的算法。但是，由于现阶段量子比特数量的限制，该算法无法处理大规模问题，且该算法的运行时间随着问题规模的增大，成指数增长。关于量子近似优化算法更详细的讨论见 [1]。\n",
    "\n",
    "分治法（divide-and-conquer, DC）是可以解决上述瓶颈的一种方法。主要是将一个大问题拆分若干个相似的子问题，将这些子问题解决之后再将子问题合并，从而得到母问题的解。Junde Li 等人在2021年提出量子近似优化的分治算法 [2] 将上述技术应用于解决较大规模的最大割问题。本教程所使用的方法在该论文的基础之上做出了一些改进。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 具体算法"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 大图分割\n",
    "\n",
    "在图论中，我们用一个图形的边 $E$ 和顶点 $V$ 定义一个图形 $G=(V,E)$。假设它有 $|V| = n$ 个顶点，但是含噪中型量子（noisy intermediate-scale quantum, NISQ）设备上最多可以运行 $k$ 个量子比特（$n > k$）。这种情况下，我们使用``大图分割 LGP``的方法将图形 $G$ 拆分两个子图 $G_0$ 和 $G_1$。为了防止遗漏任意一条边，在拆分的时候至少有一个点被两个子图共同拥有。我们把这些共有的顶点叫做分离顶点（集合），并且约束这个集合的大小小于 $k$。以下的代码定义了如何进行大图分割。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-16T03:41:44.449329Z",
     "start_time": "2021-05-16T03:41:43.034272Z"
    }
   },
   "outputs": [],
   "source": [
    "import networkx as nx # networkx的版本 >= 2.5\n",
    "import matplotlib.pyplot as plt\n",
    "from itertools import combinations\n",
    "\n",
    "# 将一个图形分割成两个有重合的分离顶点子图\n",
    "def NaiveLGP(g, k):\n",
    "    E = list(g.edges)\n",
    "    E = [(min([u, v]),max([u, v])) for (u, v) in E]\n",
    "    E.sort(key=lambda tup:tup[0])\n",
    "    V = list(g.nodes)\n",
    "    V.sort()\n",
    "\n",
    "    counter = 1\n",
    "    while counter < k:\n",
    "        num_nodes = counter\n",
    "        nodes_combo = list(combinations(V, num_nodes))\n",
    "        # 找有效的分离顶点\n",
    "        for p in nodes_combo:\n",
    "            V1 = [x for x in V if x not in p]\n",
    "            E1 = [e for e in g.edges if e not in g.edges(p)]\n",
    "            G1 = nx.Graph()\n",
    "            G1.add_nodes_from(V1)\n",
    "            G1.add_edges_from(E1)\n",
    "            S = [G1.subgraph(c).copy() for c in nx.connected_components(G1)]\n",
    "            if len(S) == 2:\n",
    "                # 将分离顶点加入不相连的子图中\n",
    "                V_S0 = list(S[0].nodes)\n",
    "                E_S0 = list(S[0].edges)   \n",
    "                V_S1 = list(S[1].nodes)\n",
    "                E_S1 = list(S[1].edges)\n",
    "                for (u, v) in g.edges(p):\n",
    "                    if u in V_S0 or v in V_S0:\n",
    "                        S[0].add_edges_from([(u, v)])\n",
    "                    if u in V_S1 or v in V_S1:\n",
    "                        S[1].add_edges_from([(u, v)])\n",
    "                    if u in p and v in p:\n",
    "                        S[0].add_edges_from([(u, v)])\n",
    "                        S[1].add_edges_from([(u, v)])\n",
    "\n",
    "                return S\n",
    "\n",
    "        counter += 1\n",
    "    print(\"G的连接度大于k\")\n",
    "\n",
    "    return {}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们给了以下的例子去说明``大图分割``是如何进行的。假设一个随机图形有10个顶点，但是 NISQ 设备最多支持9个量子比特，即 $k=9$。那么根据``大图分割``，红色的顶点0和2将被选为分离顶点。首先将这些分离顶点去掉，剩下的图将是一个不连接图形并可以被分成两个子图，比如下图中的顶点3-9和顶点1。随后，我们再将这些分离顶点和相关边分别加回两个子图中，从而保证所有的边都不会被遗漏。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-16T03:41:44.839484Z",
     "start_time": "2021-05-16T03:41:44.455664Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1080x288 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 生成一个有 10 个顶点的图形\n",
    "n = 10\n",
    "G = nx.Graph()\n",
    "G.add_nodes_from([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\n",
    "G.add_edges_from([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5),\n",
    "                  (5, 6), (6, 7), (7, 8), (8, 9), (9, 0)])\n",
    "    \n",
    "k = 9 # 设定量子比特的最大数量\n",
    "S = NaiveLGP(G,k) # 利用大图分割对图形 G 进行分割\n",
    "sep_node = list(set(S[0].nodes).intersection(set(S[1].nodes))) # 找到分离顶点\n",
    "\n",
    "# 图形示例\n",
    "options = {\n",
    "    \"with_labels\": True,\n",
    "    \"font_color\": \"white\"\n",
    "}\n",
    "node_color1 = [\"red\" if i in sep_node else \"blue\" for i in range(n)]\n",
    "node_color2 = [\"red\" if list(S[0].nodes)[i] in sep_node else \"blue\" for i in range(len(S[0].nodes))]\n",
    "node_color3 = [\"red\" if list(S[1].nodes)[i] in sep_node else \"blue\" for i in range(len(S[1].nodes))]\n",
    "\n",
    "fig, ax = plt.subplots(1, 3, figsize=(15, 4))\n",
    "for i, a in enumerate(ax):\n",
    "    a.axis('off')\n",
    "    a.margins(0.20)\n",
    "nx.draw_networkx(G, pos=nx.circular_layout(G), ax=ax[0], **options, node_color=node_color1)\n",
    "nx.draw_networkx(S[0], pos=nx.circular_layout(S[0]), ax=ax[1], **options, node_color=node_color2)\n",
    "nx.draw_networkx(S[1], pos=nx.circular_layout(S[1]), ax=ax[2], **options, node_color=node_color3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "值得提醒的一点是，我们的例子中 $k=9$，``大图分割``得到的两个子图的顶点数都小于或等于 $k$，那么两个子图的最大割问题可以直接被``量子近似优化算法``解决。但如果得到的子图的顶点数依然大于 $k$，那我们将对子图重复之前的做法，直至所有的子图顶点都小于或等于 $k$。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 图形重构\n",
    "\n",
    "当``量子近似优化（分治）算法``被应用到分离的子图上之后，所有的顶点会被分成两个部分，即 $S_0$ 和 $S_1$。我们需要将子图的最大割进行整合，得到母图的最大割。因为两个子图有共同的顶点，即分离顶点，我们要确保它们所在的最大割集合吻合，即 $S_0$ 还是 $S_1$ 需要吻合。比如，如果对于一个子图来说，分离顶点在它的最大割当中所在的分割集合都是 $S_0$，而另一个子图的最大割中，分离顶点们在的分割集合是 $S_1$，那么相应的两个最大割将不能被整合。所以为了解决这一问题，对于每个子图，我们将提供多个可能的最大割，从而在这些可能的最大割当中寻找可以整合的且可能性最高的进行整合，从而得到母图的最大割。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-16T03:41:46.108438Z",
     "start_time": "2021-05-16T03:41:45.970323Z"
    }
   },
   "outputs": [],
   "source": [
    "def GR(str_cnt1, str_cnt2):\n",
    "    com_cnt = []\n",
    "    n = len(str_cnt1[0][0])\n",
    "    com_index = []\n",
    "    for i in range(n):\n",
    "        if str_cnt1[0][0][i] != \"x\" and str_cnt2[0][0][i] != \"x\":\n",
    "            com_index.append(i)\n",
    "\n",
    "    for (str1, cnt1) in str_cnt1:\n",
    "        for (str2, cnt2)  in str_cnt2:           \n",
    "            # 检查分离顶点在两个子图所在的集合是否一致\n",
    "            validity = [str1[i] == str2[i] for i in com_index]\n",
    "            if False not in validity:\n",
    "                com_str = [[0]] * n\n",
    "                for i in range(n):\n",
    "                    if str1[i] != \"x\":\n",
    "                        com_str[i] = str(str1[i])\n",
    "                    else:\n",
    "                        com_str[i] = str(str2[i])\n",
    "                com_cnt.append((\"\".join(com_str), min(cnt1, cnt2)))\n",
    "\n",
    "    # 将{最大割：频率}按频率从大到小排列\n",
    "    com_cnt.sort(key=lambda tup:tup[1])\n",
    "    return com_cnt[::-1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们将延续上述10个顶点的圆的例子对``图形重构（graph reconstruction, GR）``进行说明。对于所分得的两个子图，我们先用``量子近似优化算法``求解最大割，再用``图形重构``将子图的最大割整合，得到原图的最大割。下面所给的代码实现了这一步骤。代码中的参数 $t$，代表想要保留最有可能的最大割的数量。如果 $t$ 大于 $2^n$，那么所有可能的最大割，即所有可能的顶点分类，都将被保留用于整合。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-16T03:42:41.303385Z",
     "start_time": "2021-05-16T03:41:47.071053Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第一个子图的最大割：\n",
      "{'010xxxxxxx': 0.49999449162430293, '101xxxxxxx': 0.49999449162430293, '000xxxxxxx': 2.4202658690211183e-06, '111xxxxxxx': 2.420265869021086e-06, '110xxxxxxx': 1.544054913842632e-06, '011xxxxxxx': 1.5440549138425979e-06, '001xxxxxxx': 1.5440549138425754e-06, '100xxxxxxx': 1.5440549138424998e-06}\n",
      "第二个子图的最大割：\n",
      "{'0x01010101': 0.14011845299520287, '1x10101010': 0.1401184529952028, '1x01010010': 0.04249785377879272, '0x10100101': 0.04249785377879272, '1x01011010': 0.0424978537787927, '0x10101101': 0.0424978537787927, '0x10101001': 0.036328002709709005, '1x01001010': 0.036328002709709, '0x10110101': 0.036328002709709, '1x01010110': 0.03632800270970896}\n",
      "母图的最大割：\n",
      "{'0101010101': 0.14011845299520287, '1010101010': 0.1401184529952028, '0001010101': 2.4202658690211183e-06, '1110101010': 2.420265869021086e-06, '1101010110': 1.544054913842632e-06, '1101001010': 1.544054913842632e-06, '1101011010': 1.544054913842632e-06, '1101010010': 1.544054913842632e-06, '0110110101': 1.5440549138425979e-06, '0110101001': 1.5440549138425979e-06}\n"
     ]
    }
   ],
   "source": [
    "# 我们利用 量子近似优化算法 计算上面例子两个子图的最大割\n",
    "# 在下一小章中，我们将使用 量子近似优化分治算法 计算子图的最大割，因为子图顶点数量有可能超过量子比特的限制。\n",
    "import paddle\n",
    "from paddle_quantum.QAOA.maxcut import find_cut\n",
    "\n",
    "# 设定 量子近似优化算法 中的参数\n",
    "p = 3     # 量子电路的层数\n",
    "ITR = 100 # 训练迭代的次数\n",
    "LR = 0.5  # 基于梯度下降的优化方法的学习率\n",
    "# 设定 图形重构 中的参数\n",
    "t = 10    # 想要保留最有可能的最大割的数量\n",
    "paddle.seed(999)  # 固定随机种子\n",
    "\n",
    "# 图形重构完整过程\n",
    "S_str_cnt = []\n",
    "for si in S:\n",
    "    siv = list(si.nodes)\n",
    "     \n",
    "    # 计算子图的最大割\n",
    "    tmp, si_str_cnt_relabeled = find_cut(si, p, ITR, LR)\n",
    "    \n",
    "    # 填充子图的最大割结果，使它们和原图的顶点数量和顺序吻合\n",
    "    si_str_cnt = []\n",
    "    for str_relabeled in si_str_cnt_relabeled:\n",
    "        strr = \"\"\n",
    "        for i in range(len(G.nodes)):\n",
    "            if i in siv:\n",
    "                strr += str_relabeled[siv.index(i)]\n",
    "            else:\n",
    "                strr += \"x\"\n",
    "        si_str_cnt.append((strr, si_str_cnt_relabeled[str_relabeled]))\n",
    "    si_str_cnt.sort(key=lambda tup:tup[1])\n",
    "    S_str_cnt.append(si_str_cnt[::-1][:t])\n",
    "\n",
    "# 当子图的最大割被找到之后，我们开始图形重构这一步\n",
    "print(\"第一个子图的最大割：\\n\" + str(dict(S_str_cnt[0])))\n",
    "print(\"第二个子图的最大割：\\n\" + str(dict(S_str_cnt[1])))\n",
    "out_cnt = GR(S_str_cnt[0], S_str_cnt[1])\n",
    "print(\"母图的最大割：\\n\" + str(dict(out_cnt[:t])))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "就以上例子来说，对于第一个子图而言，最有可能的几个最大割将包括 {'010xxxxxxx','101xxxxxxx'}，而第二个子图最有可能的最大割将包括 {'1x10101010','0x01010101'}。这些字符串中的 'x' 代表不在这个子图却在母图的顶点。从这个例子中我们看到，分离顶点0和2在第一个子图中可能的最大割，'010xxxxxxx'，中都属于 $S_0$，但它们在第二个子图的最大割，'1x10101010'，中都属于 $S_1$，所以它们无法整合。（虽然因为 $S_0$ 和 $S_1$ 的对称性，我们可以把他们进行反转从而进行整合，但是没有必要这么做。）\n",
    "\n",
    "我们接着尝试整合第一个子图的第一个最大割 '010xxxxxxx' 和第二个子图的第二个最大割 '0x01010101'，此最大割即是'101xxxxxxx' 的对称组。我们发现在这两个字符串所代表的最大割当中，分离顶点0和2都属于 $S_0$，我们也可以从下图第一张和第二张图中看出。所以我们可以整合这两个最大割并得到母图的最大割，'0101010101'，如下图第三张图所示。\n",
    "\n",
    "以下为图形展示，前两个图为两个子图的最大割实例，最右的图为母图的最大割。红色点和蓝色点分别表示被分在在 $S_0$ 和 $S_1$ 中的顶点，虚线表示被切割的边。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-16T03:42:41.647686Z",
     "start_time": "2021-05-16T03:42:41.309407Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 1080x288 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 计算出的两个子图的最大割\n",
    "strr1 =  '010xxxxxxx'\n",
    "strr2 = '0x01010101' \n",
    "strr = '0101010101'\n",
    "\n",
    "# 图形示例展示\n",
    "options0 = {\n",
    "    \"node_color\": [\"red\" if strr1[i] == '0' else \"blue\" for i in S[0].nodes],\n",
    "    \"style\": [\"solid\" if strr1[u] == strr1[v] else \"dashed\" for (u, v) in list(S[0].edges)]\n",
    "}\n",
    "options1 = {\n",
    "    \"node_color\": [\"red\" if strr2[i] == '0' else \"blue\" for i in S[1].nodes],\n",
    "    \"style\": [\"solid\" if strr2[u] == strr2[v] else \"dashed\" for (u, v) in list(S[1].edges)]\n",
    "}\n",
    "options2 = {\n",
    "    \"node_color\": [\"red\" if strr[i] == '0' else \"blue\" for i in range(n)],\n",
    "    \"style\": [\"solid\" if strr[u] == strr[v] else \"dashed\" for (u, v) in list(G.edges)]\n",
    "}\n",
    "\n",
    "fig, ax = plt.subplots(1, 3, figsize=(15,4))\n",
    "for i, a in enumerate(ax):\n",
    "    a.axis('off')\n",
    "    a.margins(0.20)\n",
    "nx.draw_networkx(S[0], pos=nx.circular_layout(S[0]), ax=ax[0], **options, **options0)\n",
    "nx.draw_networkx(S[1], pos=nx.circular_layout(S[1]), ax=ax[1], **options, **options1)\n",
    "nx.draw_networkx(G, pos=nx.circular_layout(G), ax=ax[2], **options, **options2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 量子近似优化分治法\n",
    "\n",
    "为了找到一个大图 $G$ 的最大割，我们采用``量子近似优化分治法``。这个方法像上面描述的一样，先递归性地利用``大图分割``分割图形，再利用``图形重构``递归性地整合两个子图的最大割。\n",
    "\n",
    "首先如果输入图形的顶点数大于量子比特数量限制 $k$，它将被``大图分割``分成两个子图。反之，可以直接求解它的最大割（不用拆分）。每一个子图将递归性地被输入进``量子近似优化分治法``，直到它的最大割被返回。最大割被返回说明在某一步，它某些递归的子图的顶点数量小于$k$，直接被``量子近似优化分治法``解得，再一层一层地经历``图形重构``，直到返回这个子图所在层。\n",
    "\n",
    "下面是利用``图形重构``和``大图分割``完成的``量子近似优化分治法``的代码。``量子近似优化分治法``将返回最有可能的最大割和前 $t$ 个最有可能的最大割。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-16T03:44:13.784486Z",
     "start_time": "2021-05-16T03:42:41.653981Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最有可能的 t 个图形 G 的最大割: {'0101010101': 947, '1010101010': 920, '1001010010': 150, '1001010100': 150, '1001010110': 150, '1101010010': 136, '1101010100': 136, '1101010110': 136, '1101010101': 135, '1001010101': 135}\n",
      "量子近似优化分治算法找到的图形 G 的（最有可能的）最大割: 0101010101\n"
     ]
    }
   ],
   "source": [
    "def DC_QAOA(g, p, t, s, k, ITR, LR):\n",
    "    if len(g.nodes) > k:\n",
    "        # 利用 大图分割 得到两个子图\n",
    "        S = NaiveLGP(g, k)\n",
    "\n",
    "        S_str_cnt = []\n",
    "        for si in S:\n",
    "            siv = list(si.nodes)\n",
    "            # 递归性地计算子图的最大割\n",
    "            _, si_str_cnt_relabeled = DC_QAOA(si, p, t, s, k, ITR, LR)\n",
    "            # 填充子图的最大割结果，使其和母图的顶点吻合\n",
    "            si_str_cnt = []\n",
    "            for str_relabeled in si_str_cnt_relabeled:\n",
    "                strr = \"\"\n",
    "                for v in g.nodes:\n",
    "                    if v in siv:\n",
    "                        strr += str_relabeled[siv.index(v)]\n",
    "                    else:\n",
    "                        strr += \"x\"     \n",
    "                si_str_cnt.append((strr, si_str_cnt_relabeled[str_relabeled]))\n",
    "            si_str_cnt.sort(key = lambda tup:tup[1])\n",
    "            S_str_cnt.append(si_str_cnt[::-1][:t])\n",
    "\n",
    "        # 利用 图形重构 整合子图最大割\n",
    "        out_cnt = GR(S_str_cnt[0], S_str_cnt[1])\n",
    "    else:\n",
    "        if len(g.nodes) == 1:\n",
    "            return [(\"0\", 99999), (\"1\", 99999)]\n",
    "        _, out_cnt = find_cut(g, p, ITR, LR, shots=3000)\n",
    "        # 将词典格式转成列表格式，易于排序\n",
    "        out_cnt = [(k, v) for k, v in out_cnt.items()]\n",
    "        # 将{最大割：频率}按频率从大到小排列\n",
    "        out_cnt.sort(key=lambda tup:tup[1])\n",
    "        out_cnt = out_cnt[::-1]\n",
    "\n",
    "    # 只保留最有可能的t个最大割\n",
    "    out_cnt = out_cnt[:t]\n",
    "    # 等比例调节频率的显示\n",
    "    cnt_sum = sum(cnt for (str,cnt) in out_cnt)\n",
    "    out_cnt = [(k, int(s * v / cnt_sum)) for (k, v) in out_cnt]\n",
    "\n",
    "    return out_cnt[0][0], dict(out_cnt)\n",
    "    \n",
    "# 设定 量子近似优化算法 中的参数\n",
    "p = 2     # 量子电路的层数\n",
    "ITR = 100 # 训练迭代的次数\n",
    "LR = 0.5  # 基于梯度下降的优化方法的学习率\n",
    "\n",
    "# 设定 量子近似优化分治算法 中的参数\n",
    "s = 3000  # 等比例调节频率的比例\n",
    "t = 10    # 想要保留最有可能的最大割的数量\n",
    "k = 5     # 量子比特的数量限制\n",
    "\n",
    "# 量子近似优化分治算法使用\n",
    "max_cut, out_cnt = DC_QAOA(G, p, t, s, k, ITR, LR)\n",
    "print(\"最有可能的 t 个图形 G 的最大割: \" + str(out_cnt))\n",
    "print(\"量子近似优化分治算法找到的图形 G 的（最有可能的）最大割: \" + str(max_cut))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 应用范围\n",
    "\n",
    "**以上表述的``量子近似优化分治法``可以估计一个图形的最大割，当且仅当，它和它递归出来的顶点数量大于 $k$，且子图的伪连接度（pseudo-connectivity）都小于 $k$**。伪连接度的定义为：一个连接图变成不连接的两个子图所需要移除的最小的顶点数量。\n",
    "\n",
    "当 $k > 1$ 的时候，圆圈就是一个例子。因为只需要移除两个点，圆圈就会被拆成两条不相连的子图，所以所有圆圈的伪连接度都是2。我们拿六个顶点的圆 $C_6$ 并且 $k=4$ 举例。``大图分割``会将它分成 $P_5$（顶点数量为5的子图）和 $P_2$，$P_2$ 的顶点数量在 $k$ 之下，可以直接使用``近似优化算法``计算。而子图 $P_5$ 是一个链状结构，他的伪连接度是 $1 < k$。所以``大图分割``将继续分割 $P_5$，并把它分成了 $P'_4$ 和 $P'_2$。新的子图的顶点数量都小于或等于 $k$，我们都不再需要考虑他们伪连接度。\n",
    "\n",
    "``量子近似优化分治法``不可解的图包括顶点数量大于 $k$ 的完全图（complete graph）。对于完全图来说，无论怎么移除顶点，剩余的图都是连接图。有些图是否适用决定于 $k$ 的大小，我们以下给了个这样的例子。\n",
    "\n",
    "最左的图就是实例图，这个图的伪连接度是2。如果 $k=2$，那么分离点的数量只能为1个，如果分离点是4,那么这个图被拆分成三部分而不是两部分（下图中间所示）；如果分离点是其他的几个，这个图仍然连在一起，没有被拆开。此外，该图的伪连接度为2并不小于 $k$，不满足条件，所以``量子近似优化分治法``并不适用于这个例子。但如果 $k=3$，伪连接度是 $2 < k$，这个图可以进行拆分成两个子图，其中一个的顶点数量小于等于 $k$，另一个的伪连接度显而易见是 $1<k$（移除顶点4）。``量子近似优化分治法``在这种情况下可以解决这个图。于是我们移除顶点0和4（如下图最右所示），剩下的图将是两个不相连的子图。我们再将分离顶点0和4加回去，并在这两个子图上计算最大割。``量子近似优化分治法``最终可以成功给出最大割。\n",
    "\n",
    "![limitations-connectivity](./figures/dcqaoa-fig-applicability_example.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "读者可以在以下代码中自己调试 $k$，利用``量子近似优化分治法``试验上述的示例图的最大割，从而感受这个方法的适用范围。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-16T03:44:54.150187Z",
     "start_time": "2021-05-16T03:44:13.788802Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "最有可能的 t 个图形 G 的最大割：{'00101': 549, '10110': 512, '00001': 510, '11110': 501, '01001': 471, '11010': 457}\n"
     ]
    }
   ],
   "source": [
    "G = nx.Graph()\n",
    "G.add_nodes_from([0, 1, 2, 3, 4])\n",
    "G.add_edges_from([(0, 4), (1, 2), (1, 4), (2, 4), (3, 4)])\n",
    "k = 3\n",
    "_, out_cnt = DC_QAOA(G, p, t, s, k, ITR, LR)\n",
    "print(\"最有可能的 t 个图形 G 的最大割：\" + str(dict(out_cnt)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 算法测试效果\n",
    "\n",
    "下面，我们比较量子近似优化分治法所得到的最大割和半正定规划（SDP）方法得到的理论上界进行比较。这里，我们用的例子是10个顶点的随机图，量子比特数量限制 $k=5$。\n",
    "\n",
    "为了能正确运行以下测试代码，用户首先应该安装 cvxpy：`pip install cvxpy`。**Windows 如果直接使用 pip 安装，在运行时可能会出现报错，建议新建 conda 环境后使用 conda 安装 cvxpy。**更多详情请参考 [https://www.cvxpy.org/install/](https://www.cvxpy.org/install/)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T07:06:44.690385Z",
     "start_time": "2021-05-11T07:06:44.433742Z"
    }
   },
   "outputs": [],
   "source": [
    "import cvxpy as cvx\n",
    "import networkx as nx\n",
    "\n",
    "def sdp_solver(G):\n",
    "    \"\"\"\n",
    "    通过半正定规划 SDP 来找到最大割问题的理论上界。\n",
    "    \"\"\"\n",
    "    n = len(G)\n",
    "    adj_mat = nx.adjacency_matrix(G).toarray()\n",
    "    Y = cvx.Variable((n, n), PSD=True)\n",
    "    cut_size = 0.25 * cvx.sum(cvx.multiply(adj_mat, 1 - Y))\n",
    "    problem = cvx.Problem(cvx.Maximize(cut_size), [cvx.diag(Y) == 1])\n",
    "    opt_val = problem.solve(cvx.SCS)\n",
    "\n",
    "    return opt_val"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T07:16:56.698522Z",
     "start_time": "2021-05-11T07:06:44.697731Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "顶点数量 = 10\n",
      "顶点编号 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
      "\n",
      "随机图形 1\n",
      "边 = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (2, 3), (2, 4), (2, 7), (3, 8), (3, 9), (4, 5), (5, 6), (5, 9), (6, 7), (6, 8)]\n",
      "半正定规划找的最大割的上限: 14.773421849579332\n",
      "量子近似优化分治算法找到的最大割分类: 0011011000, 最大割 = 14.0\n",
      "\n",
      "随机图形 2\n",
      "边 = [(0, 1), (0, 2), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (1, 4), (1, 6), (1, 7), (1, 8), (2, 4), (2, 5), (2, 7), (2, 9), (3, 6), (3, 8), (3, 9), (4, 5), (4, 6), (5, 7), (6, 9), (7, 9)]\n",
      "半正定规划找的最大割的上限: 17.637249299053625\n",
      "量子近似优化分治算法找到的最大割分类: 1010011010, 最大割 = 15.0\n",
      "\n",
      "随机图形 3\n",
      "边 = [(0, 1), (0, 2), (0, 4), (0, 5), (0, 7), (0, 8), (0, 9), (1, 4), (1, 5), (2, 7), (2, 8), (2, 9), (3, 5), (3, 6), (3, 8), (3, 9), (4, 5), (4, 6), (4, 9), (5, 6), (5, 8), (5, 9), (6, 7), (7, 8), (7, 9)]\n",
      "半正定规划找的最大割的上限: 19.048588813917966\n",
      "量子近似优化分治算法找到的最大割分类: 0010110100, 最大割 = 17.0\n",
      "\n",
      "随机图形 4\n",
      "边 = [(0, 3), (0, 6), (0, 7), (0, 8), (0, 9), (1, 2), (1, 5), (1, 7), (2, 6), (2, 7), (3, 4), (3, 7), (3, 8), (3, 9), (4, 5), (4, 8), (4, 9), (5, 6), (5, 9), (6, 7), (7, 9), (8, 9)]\n",
      "半正定规划找的最大割的上限: 16.551132643953018\n",
      "量子近似优化分治算法找到的最大割分类: 1010110100, 最大割 = 16.0\n",
      "\n",
      "随机图形 5\n",
      "边 = [(0, 2), (0, 5), (0, 6), (0, 7), (0, 8), (1, 2), (1, 4), (1, 7), (2, 4), (2, 7), (2, 9), (3, 4), (3, 5), (3, 6), (3, 9), (4, 6), (4, 7), (4, 8), (5, 6), (5, 7), (5, 9), (6, 8), (7, 8), (8, 9)]\n",
      "半正定规划找的最大割的上限: 18.19997280321202\n",
      "量子近似优化分治算法找到的最大割分类: 1100110001, 最大割 = 17.0\n"
     ]
    }
   ],
   "source": [
    "n = 10\n",
    "iter = 5\n",
    "print(\"顶点数量 = \" + str(n))\n",
    "print(\"顶点编号 = \" + str([i for i in range(n)]))\n",
    "\n",
    "value_dc_qaoa_ls = []\n",
    "ubound_sdp_ls = []\n",
    "for i in range(iter):\n",
    "        print(\"\\n随机图形 \" + str(i+1))\n",
    "        # 生成随机图形\n",
    "        G = nx.erdos_renyi_graph(n, 0.1, 100 * i, directed=False)\n",
    "        while nx.is_connected(G) == False:\n",
    "            G = nx.erdos_renyi_graph(n, 0.5, directed=False)\n",
    "        print(\"边 = \" + str(list(G.edges)))\n",
    "        \n",
    "        # 半正定规划（SDP）方法找最大割的上限\n",
    "        ubound_sdp = sdp_solver(G)\n",
    "        ubound_sdp_ls.append(ubound_sdp)\n",
    "        print(\"半正定规划找的最大割的上限: \" + str(ubound_sdp))\n",
    "\n",
    "\n",
    "        # 设定 量子近似优化算法 中的参数\n",
    "        p = 2      # 量子电路的层数\n",
    "        ITR = 100  # 训练迭代的次数\n",
    "        LR = 0.5   # 基于梯度下降的优化方法的学习率\n",
    "        # 设定 量子近似优化分治算法 中的参数\n",
    "        s = 3000   # 等比例调节频率的比例\n",
    "        t = 10     # 想要保留最有可能的最大割的数量\n",
    "        k = 5      # 量子比特的数量限制\n",
    "\n",
    "        try:\n",
    "            cut_dc_qaoa, out_cnt = DC_QAOA(G, p, t, s, k, ITR, LR)\n",
    "            cut_dc_qaoa1 = [\"solid\" if cut_dc_qaoa[u] == cut_dc_qaoa[v] else \"dashed\" for (u, v) in list(G.edges)]\n",
    "            value_dc_qaoa = cut_dc_qaoa1.count(\"dashed\")\n",
    "            value_dc_qaoa_ls.append(value_dc_qaoa)\n",
    "            print(\"量子近似优化分治算法找到的最大割分类: \" + str(cut_dc_qaoa) + \", 最大割 = \" + str(float(value_dc_qaoa))) \n",
    "        except Exception as e:\n",
    "            value_dc_qaoa = 0\n",
    "            value_dc_qaoa_ls.append(value_dc_qaoa)\n",
    "            print(\"量子近似优化分治算法找最大割失败，错误信息：'\" + str(e) + \"'\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-05-11T07:16:56.935061Z",
     "start_time": "2021-05-11T07:16:56.704158Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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TzoXjn983LmgXIC89NJLNGnShObNm9OyZUsWLFgAQIcOHWjQoMGZMsv33XcfCQkJZ96XXk+nadOm3HLLLZmWanZThw4dCGRX861bt9K0adM8r8cSvwlfqhA3AUa0h8NboeenTl0dNxSKgB6joGQlp5jb8YPuxBFg8+bNY8qUKSxZsoTly5fz66+/Ur36X72mPvvsM5YvX87y5cspWrTo30o3FCtWjLi4OFauXEmRIkUYMcL9Ci++1P4JBZb4TXhShW/vhcl3QZWWTnG1Ri7XXile1qn3c2wfLBnjbiwBsmfPHsqXL0/RokUBKF++PFWqVDlnuSJFivDqq6+yfft2li07d2Cb9u3bs3HjxnOmlyxZ8szzSZMmMWDAAAAGDBjAXXfdRWxsLPXr12fKlCkAjBkzhu7du9OhQwfq1avH888/f+b948aNo02bNrRs2ZI777zzTJIvWbIkjz76KC1atGDevHnnxPDpp5+eOTNZuHAhAIcOHeKGG26gefPmtGvXjuXLlwPw3HPP8dprr515b9OmTdm6dStbt26lUaNGDBkyhCZNmtC1a1dOnjwJcKY+UYsWLXj33Xez2Nu+s8RvwpOI00Wz47+cMsplqrkdkaNqaxgyAy59xJ3tf3ztuY+FI515p09kPH/pZ8784wfPnZeNrl27smPHDurXr88999zD7NmzM102IiKCFi1asHbt37u/pqSk8NNPP50pouarrVu3snDhQn744QfuuuuuM4ORL1y4kK+++orly5fz5ZdfsmjRItasWcPEiRP5448/iIuLIyIigs8+cz738ePHadu2LcuWLePSSy89ZzsnTpwgLi6O9957j0GDBgHw7LPP0qpVK5YvX87LL79Mv379so13w4YN3HvvvaxatYro6Gi++uorAAYOHMjbb7+d4Q9ibll3ThM+0tJg7ltQvj40vAYuvs/tiDJ2vieBHdoCiTvPLfMcRkqWLMnixYv5/fffmTlzJr169eKVV145c2R+Nu8SMidPnqRly5aAc8Q/ePDgHG27Z8+eFCpUiHr16lG7du0zPyhdunShXLlyANx0003MmTOHwoULs3jxYi688MIz265YsSLg/CD16NEj0+307t0bgMsuu4wjR46QkJDAnDlzziTuK664goMHD3LkSNZjIdSqVevM523dujVbt24lISGBhIQELrvsMgBuv/12fvrppxzt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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.plot(value_dc_qaoa_ls, label=\"DC-QAOA\")\n",
    "plt.plot(ubound_sdp_ls, label=\"SDP upper bound\", linestyle=\"--\")\n",
    "plt.title('Max-Cut Performancce')\n",
    "plt.xlabel('Random Graph')\n",
    "plt.ylabel('Calculated Optimal Max Cut')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "从上面的线形图中，我们可以说明``量子近似优化分治法``找到的最大割和理论上限接近。\n",
    "\n",
    "## 应用\n",
    "\n",
    "最大割问题属于应用范围很广的二次无约束二值优化（quadratic unconstrained binary optimization, QUBO）问题。此类问题的应用范围十分广泛，上至为NP-困难问题创建模型，下到找自旋玻璃的基态 [5]。同时最大割问题本身也有很广泛的应用。\n",
    "\n",
    "最大割问题和很多领域都有紧密的联系，比如超大规模集成电路（VLSI circuit）设计，统计物理。减少超大规模集成电路设计所用的孔和寻找自选玻璃基态都可以归约到最大割问题 [6]。更重要的是，最大割问题给很多算法或者技术提供了一个测试台。比如适用于最大割问题的半正定规划方法被后续用在了数据集合设计 [7] 和相位检索上 [8, 9]。\n",
    "\n",
    "更多关于最大割的应用可以在 [10-12] 里找到。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## 参考文献\n",
    "\n",
    "[1] Akshay, V., et al. \"Reachability deficits in quantum approximate optimization.\" [Physical Review Letters 124.9 (2020): 090504.](https://journals.aps.org/prl/abstract/10.1103/PhysRevLett.124.090504)\n",
    "\n",
    "[2] Li, Junde, Mahabubul Alam, and Swaroop Ghosh. \"Large-scale Quantum Approximate Optimization via Divide-and-Conquer.\" [arXiv preprint arXiv:2102.13288 (2021).](https://arxiv.org/abs/2101.03717)\n",
    "\n",
    "[3] Goemans, Michel X., and David P. Williamson. \"Improved approximation algorithms for maximum cut and satisfiability problems using semidefinite programming.\" [Journal of the ACM (JACM) 42.6 (1995): 1115-1145.](http://www-math.mit.edu/~goemans/PAPERS/maxcut-jacm.pdf)\n",
    "\n",
    "[4] Burer, Samuel, and Renato DC Monteiro. \"Local minima and convergence in low-rank semidefinite programming.\" [Mathematical Programming 103.3 (2005): 427-444.](https://link.springer.com/article/10.1007/s10107-004-0564-1)\n",
    "\n",
    "[5] Kochenberger, Gary, et al. \"The unconstrained binary quadratic programming problem: a survey.\" [Journal of Combinatorial Optimization 28.1 (2014): 58-81.](https://link.springer.com/article/10.1007/s10878-014-9734-0)\n",
    "\n",
    "[6] Barahona, Francisco, et al. \"An application of combinatorial optimization to statistical physics and circuit layout design.\" [Operations Research 36.3 (1988): 493-513.](https://www.jstor.org/stable/170992?seq=1)\n",
    "\n",
    "[7] Poland, Jan, and Thomas Zeugmann. \"Clustering pairwise distances with missing data: Maximum cuts versus normalized cuts.\" [International Conference on Discovery Science. Springer, Berlin, Heidelberg, 2006.](https://link.springer.com/chapter/10.1007/11893318_21)\n",
    "\n",
    "[8] Candes, Emmanuel J., et al. \"Phase retrieval via matrix completion.\" [SIAM review 57.2 (2015): 225-251.](https://epubs.siam.org/doi/10.1137/110848074)\n",
    "\n",
    "[9] Waldspurger, Irene, Alexandre d’Aspremont, and Stéphane Mallat. \"Phase recovery, maxcut and complex semidefinite programming.\" [Mathematical Programming 149.1 (2015): 47-81.](https://link.springer.com/article/10.1007/s10107-013-0738-9)\n",
    "\n",
    "[10] Deza, Michel, and Monique Laurent. \"Applications of cut polyhedra—I.\" [Journal of Computational and Applied Mathematics 55.2 (1994): 191-216.](https://www.sciencedirect.com/science/article/pii/0377042794900205)\n",
    "\n",
    "[11] Deza, Michel, and Monique Laurent. \"Applications of cut polyhedra—II.\" [Journal of Computational and Applied Mathematics 55.2 (1994): 217-247.](https://www.sciencedirect.com/science/article/pii/0377042794900213)\n",
    "\n",
    "[12] Poljak, Svatopluk, and Zsolt Tuza. \"Maximum cuts and largest bipartite subgraphs.\" [DIMACS Series 20 (1995): 181-244.](https://arxiv.org/pdf/1810.12144.pdf)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
